home *** CD-ROM | disk | FTP | other *** search
/ ASME's Mechanical Engine…ing Toolkit 1997 December / ASME's Mechanical Engineering Toolkit 1997 December.iso / c_lang / super_c.lzh / S2LIB.ASM < prev    next >
Assembly Source File  |  1980-01-01  |  17KB  |  387 lines

  1. ;               Serial Port Direct Interface Library
  2.  
  3.         BUFSIZE = 2000                  ; Size of buffer to use for receive
  4.  
  5. _BSS    segment word public 'BSS'       ; Global variables segment
  6. _BSS    ends
  7.  
  8. _TEXT   segment byte public 'CODE'      ; Code segment
  9. _TEXT   ends
  10.  
  11. DGROUP  group _BSS                      ; Global variables are in this group
  12.  
  13. _BSS    segment                 ; Declare variables
  14.  
  15. intSav  dw      4 dup(?)        ; Storage for saved interrupt vectors
  16. bufIn   dw      2 dup(?)        ; Buffer input pointers
  17. bufOut  dw      2 dup (?)       ; Buffer output pointers
  18. buff0   db      BUFSIZE dup(?)  ; The COM1 circular buffer
  19. buff1   db      BUFSIZE dup(?)  ; The COM2 buffer
  20.  
  21. _BSS    ends                    ; End of variables
  22.  
  23. _TEXT   segment                 ; Place the code in the code segment
  24.  
  25.         assume CS:_TEXT, DS:DGROUP ; Assume CS points to code segment, and
  26.                                    ;   DS points to DRGOUP segment (where
  27.                                    ;   the variables are)
  28.  
  29. ; _serInit(port,config)
  30. ;
  31. ; Function: Initialize and configure serial port port (0 for COM1, 1 for
  32. ; COM2). See the main text of the chapter for details on the format of the
  33. ; config parameter. Also set up incoming interrupts and buffering.
  34. ;
  35. ; Algorithm: Call the ROM BIOS to configure and initialize the port. Then
  36. ; save the existing interrupt vector and replace it with our own. Enable
  37. ; interrupts at the port, and return.
  38.  
  39.         public  _serInit        ; Routine is available to other modules
  40.  
  41.         port = 4                ; Offset from BP to parameter port
  42.         config = 6              ; Offset to parameter config
  43.  
  44. ; These two tables are used to get the buffer pointers based on the
  45. ; port number. The first table contains pointers to the beginning of
  46. ; the buffers; the second contains pointers to the first byte immediately
  47. ; after the buffers.
  48. bufAddr dw      offset DGROUP:buff0, offset DGROUP:buff1
  49. bufLim  dw      offset DGROUP:buff0+BUFSIZE, offset DGROUP:buff1+BUFSIZE
  50.  
  51. _serInit proc near              ; NEAR type subroutine
  52.         push    bp              ; Save the BP register
  53.         mov     bp,sp           ; Set BP to SP; easier to get parameters
  54.         push    di              ; Save the DI register
  55.         push    si              ; Save the SI register
  56.         mov     dx,[bp+port]    ; DX = port number
  57.         mov     al,[bp+config]  ; AL = port configuration
  58.         mov     ah,0            ; Call ROM BIOS port init function
  59.         int     14H
  60.         cli                     ; Disable interrupts
  61.         push    es              ; Save the ES register
  62.         xor     ax,ax           ; ES = 0 (to access low memory)
  63.         mov     es,ax
  64.         mov     si,[bp+port]    ; SI = port # * 2
  65.         shl     si,1
  66.         mov     ax,cs:[si+bufAddr] ; Set the buffer to empty:
  67.         mov     [si+bufIn],ax      ;   bufIn = bufOut = start of buffer
  68.         mov     [si+bufOut],ax
  69.         mov     bx,es:[si+400H] ; BX = base port address of serial port
  70.         mov     si,1            ; SI = (1 - port #) * 4 (offset to vector)
  71.         sub     si,[bp+port]
  72.         shl     si,1
  73.         shl     si,1
  74.         mov     ax,es:[si+2CH]  ; Save the old vector in intSav
  75.         mov     [si+intSav],ax
  76.         mov     ax,es:[si+2CH+2]
  77.         mov     [si+intSav+2],ax
  78.         mov     ax,OFFSET intServ ; Replace the vector with intServ
  79.         mov     es:[si+2CH],ax
  80.         mov     ax,_TEXT
  81.         mov     es:[si+2CH+2],ax
  82.         mov     dx,bx           ; Read the serial port to clear it
  83.         in      al,dx
  84.         add     dx,4            ; Enable serial port receive interrupts
  85.         in      al,dx
  86.         or      al,8
  87.         out     dx,al
  88.         sub     dx,3
  89.         mov     al,1
  90.         out     dx,al
  91.         in      al,21H          ; Enable the 8259 interrupt controller
  92.         mov     ah,0EFH
  93.         mov     cl,[bp+port]
  94.         ror     ah,cl
  95.         and     al,ah
  96.         out     21H,al
  97.         sti                     ; Enable interrupts
  98.         pop     es              ; Restore ES
  99.         pop     si              ; Restore the SI register
  100.         pop     di              ; Restore the DI register
  101.         pop     bp              ; Restore the BP register
  102.         ret                     ; Return to calling program
  103. _serInit endp                   ; End of subroutine
  104.  
  105. ; intServ
  106. ;
  107. ; Function: Serial receive interrupt service routine. Handle an interrupt
  108. ; from a serial port and return.
  109. ;
  110. ; Algorithm: Save registers. Figure out which port the interrupt is from.
  111. ; Figure out what kind of interrupt it is, and process it accordingly. 
  112. ; Acknowledge the interrupt at the 8259. Then restore registers and return
  113. ; from interrupt.
  114.  
  115. intServ proc near               ; NEAR type subroutine (doesn't matter which
  116.                                 ;   type actually, since we do a RETI rather
  117.                                 ;   than a RET)
  118.         push    ax              ; Save the AX register
  119.         push    bx              ; Save BX
  120.         push    cx              ; Save CX
  121.         push    dx              ; Save DX
  122.         push    si              ; Save SI
  123.         push    ds              ; Save DS
  124.         push    es              ; Save ES
  125.         mov     ax,DGROUP       ; Set DS to DGROUP for access to variables
  126.         mov     ds,ax
  127.         xor     ax,ax           ; Set ES to 0 for access to low memory
  128.         mov     es,ax
  129. ;
  130. ; Find which port the interrupt is from:
  131. ;
  132.         xor     si,si           ; SI = 0 (assume COM1)
  133.         mov     dx,es:400H      ; DX = base port address for COM1
  134.         add     dx,2            ; Get IIR address
  135.         in      al,dx           ; Get IIR contents
  136.         mov     ah,al           ; Make a copy of the input
  137.         and     ah,1            ; Any interrupts here?
  138.         jz      intC1           ; If there is an interrupt, go process it
  139.         mov     dx,es:402H      ; Otherwise, DX = base port address for COM2
  140.         add     dx,2            ; Get IIR address for COM2
  141.         in      al,dx           ; Get IIR contents
  142.         mov     ah,al           ; Make a copy of it
  143.         and     ah,1            ; Are there interrupts?
  144.         jnz     notC2           ; If not, forget this interrupt
  145.         add     si,2            ; If yes, increment SI for use with COM2
  146. ;
  147. ; Find out which type of interrupt it is, and handle it:
  148. ;
  149. intC1:  cmp     al,0            ; Is it a modem status change?
  150.         jne     notMSt          ; If not, try the next interrupt type
  151.         add     dx,4            ; If it is, read the modem status to clear it
  152.         in      al,dx
  153.         jmp     endInt          ; And exit
  154. notMSt: cmp     al,2            ; Is it a transmit register empty interrupt?
  155.         jne     notTRE          ; If not, try other types
  156.         jmp     endInt          ; If it is, exit (we shouldn't get these)
  157. notTRE: cmp     al,4            ; Is it a receiver register full interrupt?
  158.         jne     notRRF          ; If not, try other types
  159.         sub     dx,2            ; If yes, read in the received character
  160.         in      al,dx
  161.         call    putb            ; Put it in the buffer
  162.         jmp     endInt          ; And exit
  163. notRRF: cmp     al,6            ; Is it a receive line status interrupt?
  164.         jne     endInt          ; If not, it's no known type -- ignore it
  165.         add     dx,3            ; If yes, read the status to clear it
  166.         in      al,dx
  167. ;
  168. ; Send end-of-interrupt to the 8259:
  169. ;
  170. endInt: mov     al,20H          ; Send EOI
  171.         out     20H,al
  172. ;
  173. ; Restore registers and exit:
  174. ;
  175. notC2:  pop     es              ; Restore the ES register
  176.         pop     ds              ; Restore DS
  177.         pop     si              ; Restore SI
  178.         pop     dx              ; Restore DX
  179.         pop     cx              ; Restore CX
  180.         pop     bx              ; Restore BX
  181.         pop     ax              ; Restore AX
  182.         iret                    ; Return from interrupt
  183. intServ endp                    ; End of routine
  184.  
  185. ; serClose(port)
  186. ;
  187. ; Function: Close the port; restore it to the state it was in before serInit
  188. ; was called.
  189. ;
  190. ; Algorithm: Turn off interrupts and restore the interrupt vector to its
  191. ; original state.
  192.  
  193.         public  _serClose       ; Routine is available to other modules
  194.  
  195.         port = 4                ; Offset from BP to parameter port
  196.  
  197. _serClose proc near             ; NEAR type subroutine
  198.         push    bp              ; Save the BP register
  199.         mov     bp,sp           ; Set BP to SP; easier to access parameters
  200.         push    di              ; Save the DI register
  201.         push    si              ; Save the SI register
  202.         push    es              ; Save the ES register
  203.         xor     ax,ax           ; Set ES to 0, for access to low memory
  204.         mov     es,ax
  205.         cli                     ; Disbale interrupts
  206.         mov     si,[bp+port]    ; SI = 2*port #
  207.         shl     si,1
  208.         mov     bx,es:[si+400H] ; BX = I/O port base address
  209.         mov     si,1            ; SI = 4*(1 - port #)
  210.         sub     si,[bp+port]
  211.         shl     si,1
  212.         shl     si,1
  213.         mov     ax,[si+intSav]  ; Restore the interrupt from intSav
  214.         mov     es:[si+2CH],ax
  215.         mov     ax,[si+intSav+2]
  216.         mov     es:[si+2CH+2],ax
  217.         mov     dx,bx           ; Turn off serial interrupts
  218.         add     dx,4
  219.         in      al,dx
  220.         and     al,0F7H
  221.         out     dx,al
  222.         sub     dx,3
  223.         xor     al,al
  224.         out     dx,al
  225.         in      al,21H          ; Turn off 8259 controller ints
  226.         mov     ah,10H
  227.         mov     cl,[bp+port]
  228.         ror     ah,cl
  229.         or      al,ah
  230.         out     21H,al
  231.         mov     al,20H
  232.         out     20H,al
  233.         sti                     ; Re-enble interrupts at the processor
  234.         pop     es              ; Restore the ES register
  235.         pop     si              ; Restore SI
  236.         pop     di              ; Restore DI
  237.         pop     bp              ; Restore BP
  238.         ret                     ; Return to calling program
  239. _serClose endp                  ; End of subroutine
  240.  
  241. ; _serSend(port,char)
  242. ;
  243. ; Function: Send the character char out over serial port port.
  244. ;
  245. ; Algorithm: Wait for the transmit holding register to be empty, and then
  246. ; output the character to be sent to that register.
  247.  
  248.         public  _serSend        ; Routine is available to other modules
  249.  
  250.         port = 4                ; Offset from BP to parameter port
  251.         char = 6                ; Offset to parameter char
  252.  
  253. _serSend proc near              ; NEAR type subroutine
  254.         push    bp              ; Save the BP register
  255.         mov     bp,sp           ; Set BP to SP; easier to access parameters
  256.         push    di              ; Save the DI register
  257.         push    si              ; Save the SI register
  258.         push    es              ; Save ES
  259.         mov     dx,[bp+port]    ; DX = port #
  260.         xor     ax,ax           ; ES = 0 (for access to low memory)
  261.         mov     es,ax
  262.         mov     si,[bp+port]    ; SI = 2*port #
  263.         shl     si,1
  264.         mov     dx,es:[si+400H] ; DX = I/O port base address
  265.         add     dx,5            ; DX = address of line status register
  266. sendWt: in      al,dx           ; Get line status
  267.         and     al,20H          ; Transmit holding register empty?
  268.         jz      sendWt          ; If not, keep asking...
  269.         sub     dx,5            ; If yes, DX = address of trasmit holding reg.
  270.         mov     al,[bp+char]    ; Send character
  271.         out     dx,al
  272.         pop     es              ; Restore the ES register
  273.         pop     si              ; Restore SI
  274.         pop     di              ; Restore DI
  275.         pop     bp              ; Restore BP
  276.         ret                     ; Return to caller
  277. _serSend endp                   ; End of subroutine
  278.  
  279. ; _serRecv(port)
  280. ;
  281. ; Function: If a character is available from serial port port, return it.
  282. ; Otherwise, return -1.
  283. ;
  284. ; Algorithm: Get the port number, turn off interrupts (so one doesn't sneak
  285. ; in and mess us up), and call getb to get a character out of the input
  286. ; buffer (if there's a character available).
  287.  
  288.         public  _serRecv        ; Routine is available to other modules
  289.  
  290.         port = 4                ; Offset from BP to parameter port
  291.  
  292. _serRecv proc near              ; NEAR type subroutine
  293.         push    bp              ; Save the BP register
  294.         mov     bp,sp           ; Set BP to SP; easier to access parameters
  295.         push    di              ; Save the DI register
  296.         push    si              ; Save the SI register
  297.         mov     si,[bp+port]    ; SI = 2 * port #
  298.         shl     si,1
  299.         cli                     ; Disable interrupts
  300.         call    getb            ; Get a character from the buffer
  301.         sti                     ; Enable interrupts
  302.         pop     si              ; Restore SI register
  303.         pop     di              ; Restore DI
  304.         pop     bp              ; Restore BP
  305.         ret                     ; Return to caller
  306. _serRecv endp                   ; End of subroutine
  307.  
  308. ; _serStat(port)
  309. ;
  310. ; Function: Return the status of the serial port specified.
  311. ;
  312. ; Algorithm: Call the ROM BIOS serial status function.
  313.  
  314.         public  _serStat        ; Routine is available to other modules
  315.  
  316.         port = 4                ; Offset from BP to the parameter port
  317.  
  318. _serStat proc near              ; NEAR type subroutine
  319.         push   bp               ; Save the BP register
  320.         mov    bp,sp            ; Set BP to SP; easier to access parameters
  321.         push   di               ; Save the DI register
  322.         push   si               ; Save the SI register
  323.         mov    dx,[bp+port]     ; DX = port #
  324.         mov    ah,3             ; AH = 3 (serial status function)
  325.         int    14H              ; Call ROM BIOS serial port interrupt
  326.         pop    si               ; Restore the SI register
  327.         pop    di               ; Restore DI
  328.         pop    bp               ; Restore BP
  329.         ret                     ; Return to caller
  330. _serStat endp                   ; End of subroutine
  331.  
  332. ; putb(AL = byte, SI = offset)
  333. ;
  334. ; Function: Put a byte into a circular buffer; AL contains the byte, 
  335. ; SI contains a word offset within the buffer pointers (0 for the COM1
  336. ; buffer, 2 for the COM2 buffer). If the character didn't fit in the
  337. ; buffer, putb returns with AH == -1; otherwise AH == 0.
  338. ;
  339. ; Algorithm: Get the bufIn pointer. Compute what the new bufIn will be.
  340. ; If it equals bufOut, the buffer is full. Otherwise, the character can
  341. ; be stored and bufIn updated.
  342.  
  343. putb    proc near               ; NEAR type subroutine
  344.         mov     ah,-1           ; Assume the buffer'll be full
  345.         mov     bx,[si+bufIn]   ; BX = bufIn
  346.         mov     cx,bx           ; CX = (BX+1) modulo buffer
  347.         inc     cx              ; CX++
  348.         cmp     cx,cs:[si+bufLim] ; Is it past the end of the buffer?
  349.         jne     putb2           ; If not, continue
  350.         mov     cx,cs:[si+bufAddr] ; If yes, reset it to the beginning
  351. putb2:  cmp     cx,[si+bufOut]  ; Is the buffer full?
  352.         je      putb3           ; If it is, don't store this byte
  353.         mov     [bx],al         ; Otherwise, store the byte
  354.         xor     ah,ah           ; Set AH to indicate success
  355.         mov     [si+bufIn],cx   ; Update bufIn
  356. putb3:  ret                     ; Return
  357. putb    endp                    ; End of subroutine
  358.  
  359. ; getb(SI = offset); returns AL = char
  360. ;
  361. ; Function: Get a byte into a circular buffer; SI contains a word 
  362. ; offset within the buffer pointers (0 for the COM1 buffer, 2 for 
  363. ; the COM2 buffer). On return, AX will contain a character from the
  364. ; buffer, or -1 if there were no bytes left in the buffer.
  365. ;
  366. ; Algorithm: Get the bufOut pointer. If it equals bufIn, the buffer
  367. ; is full. Otherwise, get a byte and increment bufOut.
  368.  
  369. getb    proc near               ; NEAR type subroutine
  370.         mov     ax,-1           ; Assume we'll fail
  371.         mov     bx,[si+bufOut]  ; BX = bufOut
  372.         cmp     bx,[si+bufIn]   ; bufOut == bufIn?
  373.         je      getb2           ; If yes, go exit
  374.         mov     al,[bx]         ; Otherwise, get byte from buffer
  375.         xor     ah,ah           ; Clear top byte of AX
  376.         inc     bx              ; Increment bufOut
  377.         cmp     bx,cs:[si+bufLim] ; Past end of buffer?
  378.         jne     getb3           ; If not, continue
  379.         mov     bx,cs:[si+bufAddr] ; If yes, reset to the beginning
  380. getb3:  mov     [si+bufOut],bx  ; Update bufOut
  381. getb2:  ret                     ; Return
  382. getb    endp                    ; End of subroutine
  383.  
  384. _TEXT   ends                    ; End of code segment
  385.         end                     ; End of assembly code
  386.  
  387.